package com.afb

import org.codehaus.groovy.grails.web.context.ServletContextHolder as SCH

import java.io.BufferedWriter
import java.io.FileWriter

/**
 * Cron job like class where are definied process priorities and verifies the status of process
 */
class JobsJob {

    /* Servlet context */
    def servletContext = SCH.servletContext

    /* Execute job once in 60 seconds */
    def timeout = 60000l

    /* Process creation Date coefficient (milliseconds) */
    static final float alpha = 0.2

    /* Protein size coefficient (aminoacid number) */
    static final float beta = 0.3

    /* Number of proteins coefficient */
    static final float gamma = 0.5

    /** Maximum number of simultaneous running process */
    //    static final String MAX_NUMBER_OF_RUNNING_PROCESS = Runtime.getRuntime().availableProcessors();
    static final int MAX_NUMBER_OF_RUNNING_PROCESS = 2

    /* Path to temporary files directory (files that are created by running process) */
    String PATH_TO_TEMP_FILES_DIRECTORY
    //Tem que ser inicializada no inicio do execute.. n sei bem porque..
    //    String PATH_TO_TEMP_FILES_DIRECTORY = SCH.servletContext.getRealPath("/tmp/")

    /* Queue of processes */
    def queuedProcesses = null;

    /* Number of files to process at the next cycle */
    int numberOfFilesToProcess;

    /* File required as input of process */
    File tempFile;

    /* Email service */
    def emailerService

    // TODO The services associated with plugins should be instantiated and called dynamically..
    /** HHPred service */
    def predService

    /*
     * The rules of next to be processed are here defined. The process are ordered according to predefined coefficients weights
     *  priority = (alpha * MillisecondsofJobCreationDate) + (beta * ProteinsSize) + (gamma * NumberOfProteinsAtJob)
     *  @param numeroDeProcessos Number of processes to process from the list of queued's
     */
    def nextToBeProcessed(int numeroDeProcessos) {

        def listaQueuedPraOrdenar = Process.findAllByStatusLike("queued")

        def mapQueuedPraOrdenar = [:]

        listaQueuedPraOrdenar.each{
            mapQueuedPraOrdenar[it] = (it.job.submissionDate * alpha) + (it.input * beta) + (it.job.process.size() * gamma)
        }

        def listaQueued = mapQueuedPraOrdenar.keySet() as List;

        if (listaQueued.size()==0) return listaQueued

        int maxIndice = listaQueued.size()-1
        int indiceMaximo = (maxIndice<(numeroDeProcessos-1))?maxIndice:(numeroDeProcessos-1)

        def lista = listaQueued[0..indiceMaximo]

        def listaRetorno = lista.findAll{it!=null}

        servletContext.isListOfProcessesAltered = false;

        return listaRetorno
    }
    

    /*
     * Checks if all the process of a job have finished
     * @param job Previously submitted job
     */
    def boolean isJobFinished(Job job) {
        def procs = job.process;        
        return (procs.findAll{w -> w.status == "finished" } == procs)
    }


    def getFileName(Process p) {

//        String nomeTempFile = PATH_TO_TEMP_FILES_DIRECTORY + p.job.user.id+"_"+p.job.id+"_"+p.id;

        String nomeTempFile = p.job.user.id+"_"+p.job.id+"_"+p.id;
        return nomeTempFile;
    }

    def String readFile( String file ) throws IOException {
        FileReader fr = new FileReader(file)
        BufferedReader reader = new BufferedReader(fr);
        String line  = null;
        StringBuilder stringBuilder = new StringBuilder();
        String ls = System.getProperty("line.separator");
        while( ( line = reader.readLine() ) != null ) {
            stringBuilder.append( line );
            stringBuilder.append( ls );
        }
        
        fr.close()
        reader.close()

        return stringBuilder.toString();
    }

    /**
     * Retorna o numero de processos que acabaram de ser processados
     */
    public int checkProcessing() {

        println "check running process........................................................................................................"

        def listaProcessing = Process.findAllByStatusLike("processing")
        //        def listaQueued = Process.findAllByStatusLike("queued")
        def listaFinished = Process.findAllByStatusLike("finished")

        if (Process.list().size()==listaFinished.size()) {
            servletContext.isListOfProcessesAltered = false;
            return 0;
        }

        println "listaProcessing : " + listaProcessing

        //            println "HHPredService : " + hHPredService
        println " predService : " +predService
        println "emailerService : " + emailerService


        if (listaProcessing.size()==0) return MAX_NUMBER_OF_RUNNING_PROCESS;

        File fileInput;
        File fileOutput;
        int processedFiles = 0
        listaProcessing.each {
            //            String nomeTempFile = PATH_TO_TEMP_FILES_DIRECTORY + it.job.user.name+"_"+it.job.name+"_"+it.name+"."+PROCESSED_FILES_EXTENSION;

            Date dateNow = new Date();


            // APAGAR DAKI

            //            if (dateNow.getTime() - it.startProcessing > 900000) { // se ja estiver a ser processado a mais de 15 minutos, deve ter havido erro

            long howLongTimeProcessing = dateNow.getTime() - it.startProcessing
            //            if (howLongTimeProcessing > 900000) { // se ja estiver a ser processado a mais de 15 minutos, deve ter havido erro
            if (howLongTimeProcessing > 900000) { // se ja estiver a ser processado a mais de 15 minutos, deve ter havido erro

                println "howLongTimeProcessing : " +howLongTimeProcessing

                it.status="error"
                servletContext.isListOfProcessesAltered = true;
                processedFiles++

            } else {

                // ATE AKI

                println ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"

                //            println "HHPredService : " + hHPredService
                println "emailerService : " + emailerService


                println ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
            

                String nomeTempFile = getFileName(it)
                String nomeTempFileInput
                String nomeTempFileOutput = PATH_TO_TEMP_FILES_DIRECTORY + nomeTempFile+"."+predService.PROCESSED_FILES_EXTENSION

                println "ficheiro : " + nomeTempFile

                fileOutput = new File(nomeTempFileOutput)

                if (fileOutput.exists()) {
                    println "o ficheiro "+nomeTempFileOutput+" existe!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
                    println "o ficheiro "+nomeTempFileOutput+" existe!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
                    println "o ficheiro "+nomeTempFileOutput+" existe!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
                    println "o ficheiro "+nomeTempFileOutput+" existe!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
                    println "o ficheiro "+nomeTempFileOutput+" existe!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
                    println "o ficheiro "+nomeTempFileOutput+" existe!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
                    println "o ficheiro "+nomeTempFileOutput+" existe!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
                    Date dateFileModified = new Date(fileOutput.lastModified());

                    long elapsedTime = dateNow.getTime() - dateFileModified.getTime();

                    println "elapsedTime : "+elapsedTime;

                    if (elapsedTime>5000) {
                        it.output = readFile(nomeTempFileOutput)
                        it.status = "finished"

                        //                fich.close()

                        nomeTempFileInput = nomeTempFile+"."+predService.RUNNING_FILES_EXTENSION
                        fileInput = new File(nomeTempFileInput)
                        boolean success;

                        // APAGAR OS TODOS OS FICHEIROS CRIADOS!!!
                        //                success = fileInput.delete()
                        //
                        //                if (success) {
                        //                    println "Ficheiro " + nomeTempFile+".fasta deleted###################################################################################"
                        //                }
                        //
                        //                success = fileOutput.delete() && new File(nomeTempFile+".blast").delete() && new File(nomeTempFile+".a3m").delete() && new File(nomeTempFile+".hhm").delete()
                        //
                        //                if (success) {
                        //                    println "Ficheiro " + nomeTempFile+".hhr deleted###################################################################################"
                        //                }

                        println " ############################################################################## Vou tentar apagar os ficheiros relativos a este processo.. "
                        def dir = new File(PATH_TO_TEMP_FILES_DIRECTORY)
                        println "directoria : " + dir.absolutePath
                        println "Ficheiros : " + dir.listFiles()
                        println "Nome Ficheiro a Processar : " + nomeTempFile


//                        String path = nomeTempFile
//                        def splite = path.split("/")
//                        String firstPartFilename = splite.last().split("\\.")[0]
//                        println "FirstPartFilename : " +firstPartFilename


//                        String path = nomeTempFile
//                        def splite = path.split("/")
                        String firstPartFilename = nomeTempFile
                        println "FirstPartFilename : " +firstPartFilename




                        dir.eachFile {

                            println "ficheiro       : " + it.name
                            println "isFile()       : " + it.isFile()
                            println "Contains name  : " + it.name.contains(nomeTempFile)

                            if (it.isFile() && it.name.contains(firstPartFilename)) {
                                println "entrei no if.. "

                                //    if (it.isFile()) {
                                //        println it.canonicalPath
                                success = it.delete()
                                if (success) {
                                    println "file deleted : " + it.name
                                }
                            }
                            println "____________________________________________________________________________________________ "
                        }

                        processedFiles++;


                        if (isJobFinished(it.job)) {
                            it.job.status="finished"
                                                mensagem("cristiano_manuel@hotmail.com","testeeheh","mais bla bla");

                                                   mensagem(it.job.user.email,"Job finished","Job finished...");
                        }

                        servletContext.isListOfProcessesAltered = true;
                    }

                    // APAGAR DAKI
                }
                // ATE AKI

            }

        }

        println "vou sair daki com " + processedFiles
        return processedFiles;
    }



    // Send an email
    def mensagem(String to1, String subject1, String body1) {
        // Each "email" is a simple Map

        //        params.to = "cristiano_manuel@hotmail.com"
        //        params.subject = "teste grails"
        //        params.body = "bla bla bla"

        //        def email = [
        //            to: [ params.to ],        // "to" expects a List, NOT a single email address
        //            subject: params.subject,
        //            text: params.body         // "text" is the email body
        //        ]

        def email = [
            to: [ to1 ],        // "to" expects a List, NOT a single email address
            subject: subject1,
            text: body1         // "text" is the email body
        ]

        println "email : " + email;

        println "emailerService : "  + emailerService

        // sendEmails expects a List
        emailerService.sendEmails([email])
        //        render("done")
    }


    def execute() {

        //        PATH_TO_TEMP_FILES_DIRECTORY = SCH.servletContext.getRealPath("/tmp/")
        PATH_TO_TEMP_FILES_DIRECTORY = SCH.servletContext.getRealPath("/")

        println "e agora? PATH_TO_TEMP_FILES_DIRECTORY : " + PATH_TO_TEMP_FILES_DIRECTORY

        if (servletContext.isAvailableToProcess) {

            numberOfFilesToProcess = checkProcessing();

            println "dasss ?! numberOfFilesToProcess : " + numberOfFilesToProcess
            
            if ((servletContext.isListOfProcessesAltered)&&(numberOfFilesToProcess>0)) {
                println "Vou actualizar a lista de processos a ser processada"
                println "Vou por processos a correr"
                queuedProcesses = nextToBeProcessed(numberOfFilesToProcess);

            } else {
                println "Nao houve alteracoes na ordem dos processos a correr"
            }
            
            queuedProcesses.each {
                println "it : "+it;
                println "vou executar o processo "+ it.name;
                println "databases do job " + it.job.hmmDatabases

                //                String nomeTempFile = PATH_TO_TEMP_FILES_DIRECTORY + it.job.user.name+"_"+it.job.name+"_"+it.name+".fasta";

                String nomeTempFile = PATH_TO_TEMP_FILES_DIRECTORY + getFileName(it)+"."+predService.RUNNING_FILES_EXTENSION
                tempFile = new File(nomeTempFile);

                println "nome do ficheiro a ser verificado : " + nomeTempFile

                if (tempFile.createNewFile()) {


                    
                    //                    String proteinContents = it.input
                    Process processo = it

                    Thread.start {

                        def proc1
                        def proc2
                        def proc3
                        def proc4
                        def proc5

                        println "Consegui Criar o ficheiro!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";

                        println "Input do fichedro : " + processo.input

                        BufferedWriter bw;
                        FileWriter fw;

                        fw = new FileWriter(nomeTempFile);
                        bw = new BufferedWriter(fw);
                        String texto = processo.input;

                        bw.write(texto)
                        println "consegui escrever no ficheiro"

                        bw.close();

                        String cmd

//                        cmd = "blastpgp -i "+nomeTempFile+" -d nr70 -j 5 -h 0.001 -o "+getFileName(processo)+".bla"
//                        proc1 = cmd.execute()
//                        proc1.waitFor()
//
//                        println " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> VOU ESCREVER O QUE SE PASSA COM O BLAST=!=!="
//
//                        if (proc1.exitValue())
//                        print proc1.err.text
//                        else
//                        print proc1.text
//
//                        println " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ATE AKI......................................"
//
//                        cmd = "alignhits.pl "+getFileName(processo)+".bla "+getFileName(processo)+".a3m -a3m"
//                        proc2 = cmd.execute()
//                        proc2.waitFor()
//
//                        println " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> VOU ESCREVER O QUE SE PASSA COM O ALIGNHITS=!=!="
//
//                        if (proc2.exitValue())
//                        print proc2.err.text
//                        else
//                        print proc2.text
//
//                        println " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ATE AKI......................................"
//                        cmd = "addpsipred.pl "+getFileName(processo)+".a3m"
//                        proc3 = cmd.execute()
//                        proc3.waitFor()
//                        println " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> VOU ESCREVER O QUE SE PASSA COM O ADDPSIPRED =!=!="
//                        if (proc3.exitValue())
//                        print proc3.err.text
//                        else
//                        print proc3.text
//                        println " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ATE AKI......................................"
//
//                        cmd = "hhmake -i "+getFileName(processo)+".a3m"
//                        proc4 = cmd.execute()
//                        proc4.waitFor()
//                        println " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> VOU ESCREVER O QUE SE PASSA COM O HHMAKE =!=!="
//
//                        if (proc4.exitValue())
//                        print proc4.err.text
//                        else
//                        print proc4.text
//
//                        println " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ATE AKI......................................"

//                        cmd = "hhsearch -i " + getFileName(processo) + ".hhm -d " + predService.PATH_TO_HMM_DATABASE
                        cmd = "hhsearch -i " + nomeTempFile + " -d " + predService.PATH_TO_HMM_DATABASE

                        proc5 = cmd.execute()
                        proc5.waitFor()

                        if (proc5.exitValue())
                        print proc5.err.text
                        else
                        print proc5.text

                    }

                    it.status = "processing";
                    it.startProcessing = System.currentTimeMillis();
                    println "process "+it.name + " is running!";
                    
                } else {
                    println "Failure creating file"
                }
                //                tempFile.delete();
            }
        }
        servletContext.isListOfProcessesAltered = false
    }
}
